package com.pic.mgt.utils;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public abstract class DateConvertUtils {
	private static DateFormat dateToyyyyMMddHHmmString; // <<2011/10/20 指示檔內容時間格式變更 by Timothy>>
	private static DateFormat dateToMMddHHmmString;
	private static DateFormat dateToMMddString;
	private static NumberFormat numberFormat_00;
	
	static {
		// <<2011/10/20 指示檔內容時間格式變更 by Timothy>>
		dateToyyyyMMddHHmmString = new SimpleDateFormat("yyyyMMddHHmm");
		
		dateToMMddHHmmString = new SimpleDateFormat("MMddHHmm");
		
		dateToMMddString = new SimpleDateFormat("MMdd");
		
		numberFormat_00 = new DecimalFormat("00");
	}
	
	/**
	 * 將日期轉為字串格式 'MMdd'
	 * @param date
	 * @return
	 */
	public static String dateToMMddString(Date date) {
		return dateToMMddString.format(date);
	}
	
	/**
	 * 將日期轉為字串格式 'MMddHHmm'
	 * @param date
	 * @return
	 */
	public static String dateToMMddHHmmString(Date date) {
		return dateToMMddHHmmString.format(date);
	}
	
	/**
	 * 將日期轉為字串格式 'yyyyMMddHHmm'
	 * @param date
	 * @return
	 */
	// <<2011/10/20 指示檔內容時間格式變更 by Timothy>>
	public static String dateToyyyyMMddHHmmString(Date date) {
		return dateToyyyyMMddHHmmString.format(date);
	}
	
	/**
	 * 能夠將日期字串轉換成日期。呼叫方法需提供二個參數，第一個為日期字串，日期字串可以
	 * 只提供部份的日期欄位，不需全部提供，不提供的欄位部份會以現在時間取代；第二個參數為
	 * 日期字 串的格式，使用方式同 SimpleDateFormat，如:yyyyHHdd, HHdd, ....，目前僅支
	 * 援：yyyy, MM, dd, HH, mm, ss。
	 * @param 日期字串
	 * @param 日期字串的格式 (ex:yyyyMM)
	 * @return
	 * @throws StringIndexOutOfBoundsException
	 */
	public static Date convertToDate(String timeString, String timeFormat)
									throws StringIndexOutOfBoundsException,
										   NumberFormatException {
		Calendar cal = Calendar.getInstance();
		int indexOf;
		
		if ((indexOf = timeFormat.indexOf("yyyy")) > -1) {
			fillYear(indexOf, timeString, cal);
		}
		
		if ((indexOf = timeFormat.indexOf("MM")) > -1) {
			fillMonthInYear(indexOf, timeString, cal);
		}
		
		if ((indexOf = timeFormat.indexOf("dd")) > -1) {
			fillDayInMonth(indexOf, timeString, cal);
		}
		
		if ((indexOf = timeFormat.indexOf("HH")) > -1) {
			fillHourInDay(indexOf, timeString, cal);
		}
		
		if ((indexOf = timeFormat.indexOf("mm")) > -1) {
			fillMinute(indexOf, timeString, cal);
		}
		
		if ((indexOf = timeFormat.indexOf("ss")) > -1) {
			fillSecond(indexOf, timeString, cal);
		}
		
		return cal.getTime();
	}
	
	private static void fillYear(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException,
												   NumberFormatException {
		int endIndex = startIndex + 4;
		int year = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		if (year < 1) {
			throw new NumberFormatException("The date format of year '" + year + "' is incorrect.");
		}
		
		cal.set(Calendar.YEAR, year);
	}
	
	private static void fillMonthInYear(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException, 
												   NumberFormatException {
		int endIndex = startIndex + 2;
		int month = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		if (month > 12 || month < 1) {
			throw new NumberFormatException("The date format of month '" + month + "' is incorrect.");
		}
		
		cal.set(Calendar.MONTH, month - 1);
	}
	
	private static void fillDayInMonth(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException, 
												   NumberFormatException {
		int endIndex = startIndex + 2;
		int dayInMonth = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		int maxDayInMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		if (dayInMonth > maxDayInMonth || dayInMonth < 1) {
			throw new NumberFormatException("The date format of day '" + dayInMonth + "' is incorrect.");
		}
		
		cal.set(Calendar.DAY_OF_MONTH, dayInMonth);
	}
	
	private static void fillHourInDay(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException,
												   NumberFormatException {
		int endIndex = startIndex + 2;
		int hourInday = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		if (hourInday > 23) {
			throw new NumberFormatException("The date format of hour '" + hourInday + "' is incorrect.");
		}
		
		cal.set(Calendar.HOUR_OF_DAY, hourInday);
	}
	
	private static void fillMinute(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException, 
												   NumberFormatException {
		int endIndex = startIndex + 2;
		int minute = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		if (minute > 59) {
			throw new NumberFormatException("The date format of minute '" + minute + "' is incorrect.");
		}
		
		cal.set(Calendar.MINUTE, minute);
	}
	
	private static void fillSecond(int startIndex, String timeString, Calendar cal)
											throws StringIndexOutOfBoundsException, 
											       NumberFormatException{
		int endIndex = startIndex + 2;
		int second = Integer.valueOf(timeString.substring(startIndex, endIndex));
		
		if (second > 59) {
			throw new NumberFormatException("The date format of second '" + second + "' is incorrect.");
		}
		
		cal.set(Calendar.SECOND, second);
	}
	
	/**
	 * 將指定的字串內填入現在的日期。方法會將給定的字串內在適當的位子放入現在的日期
	 * 欄位。字串內容必須使用關鍵字來指示要將什麼日期欄位放入哪個位置。日期字 串的格式
	 * ，使用方式同 SimpleDateFormat，如:yyyy,MM,dd。僅支援年(yyyy),月(MM),日(dd)，
	 * 使用時必須以 '<' 和 '>' 二個符號括起來，如：'<yyyy>', '<MM>', '<dd>'。方法會自
	 * 動判別關鍵字的存在，並置換成為現在的日期。使用方式：
	 * String str = DateConverUtils.fillDateFieldsToString("/home/usr/test/<yyyy>/<MM><dd>");
	 * @param targetStr
	 * @return
	 */
	public static String fillDateFieldsInString(String targetStr) {
		Calendar todayCal = Calendar.getInstance();
		
		return fillDateFieldsInString(targetStr, todayCal);
	}
	
	/**
	 * 將指定的字串內填入指定的日期。方法會將給定的字串內在適當的位子放入現在的日期
	 * 欄位。字串內容必須使用關鍵字來指示要將什麼日期欄位放入哪個位置。日期字 串的格式
	 * ，使用方式同 SimpleDateFormat，如:yyyy,MM,dd。僅支援年(yyyy),月(MM),日(dd)，
	 * 使用時必須以 '<' 和 '>' 二個符號括起來，如：'<yyyy>', '<MM>', '<dd>'。方法會自
	 * 動判別關鍵字的存在，並置換成為現在的日期。使用方式：
	 * String str = DateConverUtils.fillDateFieldsToString("/home/usr/test/<yyyy>/<MM><dd>");
	 * @param targetStr
	 * @return
	 */
	public static String fillDateFieldsInString(String targetStr, Calendar cal) {
		// 填入年
		String year = String.valueOf(cal.get(Calendar.YEAR));
		targetStr = targetStr.replace("<yyyy>", year);
		
		// 填入月
		String monthOfYear = numberFormat_00.format(
								cal.get(Calendar.MONTH) + 1);
		targetStr = targetStr.replace("<MM>", monthOfYear);
		
		// 填入日
		String dayOfMonth = numberFormat_00.format(
								cal.get(Calendar.DAY_OF_MONTH));
		targetStr = targetStr.replace("<dd>", dayOfMonth);
		
		return targetStr;
	}
}
